import datetime
import os
import sys
import jqdatasdk
from django.contrib.auth import models as auth_models
from django.http import JsonResponse
from django.shortcuts import render
import pandas as pd
from django.conf import settings
from stocksys import models as stocksys_models, tasks
from stocksys.quant_rules.PredictionModel import PredictionMode
from stocksys.stocksys_forms.code_editor_forms import RuleEditorForms, RuleCreateForms, RuleDeleteForms
from stocksys.views.data_logic import getExchangeInfo, get_day_exchange_time, get_month_exchange_time, init_message, \
    frequency_analysis
from stocksys.views.user_views import check_login


# 规则预测结果
@check_login
def quant_rule_predict(request, addr, code, start_date, end_date, exchange_type):
    context = init_message(request)
    context["title"] = "量化分析系统-预测行情信息"
    context["predicction_type"] = exchange_type
    exchange = getExchangeInfo(code, exchange_type, addr)
    context["exchange"] = exchange

    now_user = auth_models.User.objects.get(id=request.session.get('id', -1))
    sysconf = stocksys_models.SysConf.objects.get(user=now_user)
    main_model = stocksys_models.ManagedCode.objects.filter(id=sysconf.main_model).first()
    rule_name = main_model.name
    context["predict_model_name"] = rule_name
    if settings.USE_JQDATA_SDK:
        predict_model = PredictionMode("stocksys.quant_rules." + rule_name + "_model")
        full_code = exchange['code'] + '.' + stocksys_models.ExchangeAddress.objects.get(
            id=exchange['address']).stock_jqdata_name
        predict_model.init_base_data(full_code, start_date, end_date, exchange_type=exchange_type)
        clf, accuracy, sources_data, forecast_data = predict_model.train_predict_save(0.01, main_model)
        forecast_data['color'] = None
        forecast_data['Chg'] = 0
        forecast_date = pd.to_datetime(forecast_data.date).dt.strftime('%Y-%m-%d').values
        forecast_price = forecast_data.Forecast.values

        forecast_data = [forecast_data.loc[x].to_dict() for x in range(len(forecast_data))]
        now_close_value = forecast_data[0]['Forecast']

        for index in range(1, len(forecast_data)):
            if forecast_data[index]['Forecast'] < now_close_value:
                forecast_data[index]['color'] = 'success'
            else:
                forecast_data[index]['color'] = 'danger'
            forecast_data[index]['Chg'] = (forecast_data[index]['Forecast'] - now_close_value) / now_close_value * 100
            now_close_value = forecast_data[index]['Forecast']

        # print(forecast_data)
        context["accuracy"] = accuracy
        context["exchange_type"] = exchange_type
        context["address"] = exchange['address']
        context["forecast_data"] = forecast_data
        context["forecast_date"] = forecast_date
        context["forecast_price"] = forecast_price
        context["frequency_analysis_image"] = frequency_analysis(sources_data, 1)
        if exchange_type == 'stock':
            exchange_address = stocksys_models.ExchangeAddress.objects.get(id=addr)
            stock = stocksys_models.Stock.objects.get(code=code, exchange_address=exchange_address)

            jqdata_code = "%s.%s" % (code, stock.exchange_address.stock_jqdata_name)

            # 获取集合竞价数据 call_auction
            start_date, end_date = get_day_exchange_time()

            api_keys = stocksys_models.APIKeys.objects.all().first()
            jqdatasdk.auth(api_keys.username, api_keys.password)

            call_auction = jqdatasdk.get_call_auction(jqdata_code, start_date, end_date, fields=None)
            call_auction = [call_auction.loc[index].to_dict() for index in range(len(call_auction))]
            context["call_auction"] = call_auction[-1]

            # 融资融券信息 mtss
            start_date, end_date = get_month_exchange_time()
            mtss = jqdatasdk.get_mtss(jqdata_code, start_date, end_date)
            mtss = [mtss.loc[index].to_dict() for index in range(len(mtss))]
            context["mtss"] = mtss[-5:-1]
            jqdatasdk.logout()
    else:
        pass
        # stock_address = stocksys_models.StockClass.objects.get(stock_class_id=addr)
        #
        # accuracy, data, save_file_base64 = base_LinearRegression(code, start_year, end_year)
        # data_forecast_predict = data['Forecast'].to_list()
        # data_forecast_date = list(map(datetime_array2string, data.index.values))
        # predicct = []
        # [predicct.append({"date": data_forecast_date[index],
        #                   "forecast": data_forecast_predict[index]
        #                   }) for index in range(len(data_forecast_date))]
        # context["accuracy"] = accuracy
        # context["stock_address"] = stock_address
        # context["predicct"] = predicct
        # context["save_file_base64"] = save_file_base64
    return render(request, "stocksys/prediction_info.html", context)


# TODO:规则列表
@check_login
def quant_rules(request):
    if request.method == "GET":
        context = init_message(request)
        context["title"] = "量化分析系统-规则列表"
        context["rule_info"] = []

        now_user = auth_models.User.objects.get(id=request.session.get('id', -1))
        sysconf = stocksys_models.SysConf.objects.get(user=now_user)
        rule_info = stocksys_models.RuleInfo.objects.filter(sysconf=sysconf)
        for rule in rule_info:
            predict_model = stocksys_models.ManagedCode.objects.filter(id=rule.id, sysconf=sysconf).first()
            predict_model = predict_model.name if predict_model != None else -1
            context["rule_info"].append({
                "id": rule.id,
                "model_name": predict_model,
                "name": rule.name,
                "create_datetime": rule.create_datetime,
                "update_datetime": rule.update_datetime,
                "max_back_measurable": rule.max_back_measurable,
                "mean_back_measurable": rule.mean_back_measurable,
            })
        context["edit_type"] = "model"
        return render(request, "stocksys/rule/rule_manage.html", context)


# TODO:编辑 保存 构建规则
@check_login
def rule_editor(request, id=None):
    user = auth_models.User.objects.get(id=request.session.get('id', -1))
    sysconf = stocksys_models.SysConf.objects.get(user=user)
    if request.method == "PUT":
        rule_editor_forms = RuleEditorForms(request.PUT)
        if rule_editor_forms.is_valid():
            rule_id = rule_editor_forms.cleaned_data['rule_id']
            rule = stocksys_models.RuleInfo.objects.get(id=rule_id)
            code_content = rule_editor_forms.cleaned_data['code']
            code_file_path = settings.BASE_DIR + '/stocksys/quant_tactics/' + rule.name_en + '_rule.py'
            with open(code_file_path, 'w') as code_file:
                code_file.write(code_content)
                rule.update_datetime = datetime.datetime.now()
                rule.code_size = len(code_content)
                rule.save()
            return JsonResponse({'state': 200, "info": "success"})
        return JsonResponse({'state': 500, "info": "error"})
    elif request.method == "GET":
        context = init_message(request)
        context["title"] = "量化分析系统-规则编辑"
        rule = stocksys_models.RuleInfo.objects.get(id=id)
        context["rule"] = rule
        code_file_path = settings.BASE_DIR + '/stocksys/quant_tactics/' + rule.name_en + '_rule.py'
        with open(code_file_path, 'r') as code_file:
            context["code_content"] = code_file.read()
            print(context["code_content"])
        return render(request, "stocksys/rule/rule_editor.html", context)
    elif request.method == 'POST':
        rule_save_forms = RuleCreateForms(request.POST)
        if rule_save_forms.is_valid():
            empty_file_path = settings.BASE_DIR + '/stocksys/quant_tactics/base_empty_rule.py'
            name_en = rule_save_forms.cleaned_data['name_en']
            name = rule_save_forms.cleaned_data['name']
            with open(empty_file_path, 'r') as empty_file:
                code_file_path = settings.BASE_DIR + '/stocksys/quant_tactics/' + name_en + '_rule.py'
                with open(code_file_path, 'w+') as code_file:
                    code_file.write(empty_file.read())
                    stocksys_models.RuleInfo.objects.create(
                        name=name,
                        name_en=name_en,
                        sysconf=sysconf
                    )
                    return JsonResponse({"statue": "200", "info": 'create success'})
        return JsonResponse({"statue": "400", "info": 'create error'})
    elif request.method == 'DELETE':
        rule_delete_forms = RuleDeleteForms(request.DELETE)
        if rule_delete_forms.is_valid():
            rule_id = rule_delete_forms.cleaned_data['rule_id']
            rule = stocksys_models.RuleInfo.objects.get(id=rule_id)
            code_file_path = settings.BASE_DIR + '/stocksys/quant_tactics/' + rule.name_en + '_rule.py'
            if os.path.exists(code_file_path):
                os.remove(code_file_path)
                rule.delete()
                return JsonResponse({"statue": "200", "info": 'delete success'})
            else:
                return JsonResponse({"statue": "403", "info": 'file not exits'})
        return JsonResponse({"statue": "400", "info": 'invalid request forms'})


# TODO:托管代码
@check_login
def managed_code(request):
    if request.method == "GET":
        context = init_message(request)
        context["title"] = "量化分析系统-托管代码"
        model_info = stocksys_models.ManagedCode.objects.all()
        context["model_info"] = model_info
        context["edit_type"] = "model"
        return render(request, "stocksys/rule/code_manage.html", context)


@check_login
def code_editor(request, id):
    if request.method == "GET":
        context = init_message(request)
        context["title"] = "量化分析系统-代码编辑"
        context["code_content"] = ""
        context["model_id"] = id
        manage_code = stocksys_models.ManagedCode.objects.get(id=id)
        code_file_path = settings.BASE_DIR + '/stocksys/quant_rules/' + manage_code.name + '_model.py'
        with open(code_file_path, 'r') as code_file:
            context["code_content"] = code_file.read()
            context["update_time"] = manage_code.update_datetime
        return render(request, "stocksys/rule/code_editor.html", context)
    elif request.method == "POST":
        code_content = request.POST.get('code', default=None)
        if len(code_content) != 0:
            manage_code = stocksys_models.ManagedCode.objects.get(id=id)
            code_file_path = settings.BASE_DIR + '/stocksys/quant_rules/' + manage_code.name + '_model.py'
            with open(code_file_path, 'w') as code_file:
                code_file.write(code_content)
                manage_code.update_datetime = datetime.datetime.now()
                manage_code.code_size = len(code_content)
                manage_code.save()
                return JsonResponse({"statue": "200", "page": sys._getframe().f_code.co_name})
        else:
            return JsonResponse({"statue": "500", "info": 'error code is empty or post error'})


# TODO:规则回测
@check_login
def back_test(request):
    return JsonResponse({"statue": "200", "page": sys._getframe().f_code.co_name})
